package org.carl.akka.core;

import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.carl.akka.annotation.EnableAkkaCore;
import org.carl.akka.base.BaseAkkaActor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;

import java.util.Objects;
import java.util.Set;

@Slf4j
public class AkkaCoreRunner implements CommandLineRunner, AkkaCore {

    @Value("${spring.application.name:akka-core}")
    private String applicationName;
    @Autowired
    private ApplicationContext applicationContext;

    @Override
    public void run(String... args) throws Exception {
        // 获取启动类的Bean定义名称，通常是"application"或"Application"
        String[] beanNamesForAnnotation = applicationContext.getBeanNamesForAnnotation(org.springframework.boot.autoconfigure.SpringBootApplication.class);
        if (beanNamesForAnnotation.length > 0) {
            String startupBeanName = beanNamesForAnnotation[0];
            // 获取启动类的Class对象
            Class<?> startupClass = applicationContext.getType(startupBeanName);
            EnableAkkaCore enableAkkaCore = AnnotationUtils.findAnnotation(startupClass, EnableAkkaCore.class);
            log.info("启动类名称:{},寻找@EnableAkkaCore结果:{}", startupBeanName, enableAkkaCore);
            if (Objects.nonNull(enableAkkaCore) && enableAkkaCore.enabled()) {
                //寻找所有AbstractActor的字类
                Set<Class<?>> classes = ClassUtil.scanPackageBySuper(enableAkkaCore.basePackage(), BaseAkkaActor.class);
//                Map<String, BaseAkkaActor> classSet = SpringUtil.getBeansOfType(BaseAkkaActor.class);
                //初始化ActorSystem
                ActorSystem actorSystem = ActorSystem.create(applicationName + "-actorSystem");
                ACTOR_SYSTEM.set(actorSystem);
                //将actorSystem注入到spring中
                SpringUtil.registerBean(actorSystem.name(), actorSystem);
                log.info("spring注册ActorSystem:{}", actorSystem);
                //将所有AbstractActor的字类注册到ActorSystem中
                for (Class<?> clazz : classes) {
                    Props props = ReflectUtil.invokeStatic(ClassUtil.getDeclaredMethod(clazz, "props"));
                    log.info("执行class:{}中的props方法,返回:{}", clazz, props);
                    if (Objects.isNull(props)) {
                        log.warn("当前class:{}中的props方法未实现将执行Props.create(clazz)创建Props", clazz);
                        props = Props.create(clazz);
                    }
                    //获取clazz的名称并首字母小写
                    String className = StrUtil.lowerFirst(ClassUtil.getShortClassName(ClassUtil.getClassName(clazz, false)));
                    //将Props对象注册到ActorSystem中
                    String actorRefName = className + ActorRef.class.getSimpleName();
                    ActorRef actorRef = actorSystem.actorOf(props, actorRefName);
                    log.info("初始化ActorRef：{},Props:{}", actorRefName, props);
                    SpringUtil.registerBean(actorRefName, actorRef);
                    ACTOR_REF_MAP.put((Class<? extends BaseAkkaActor>) clazz, actorRef);
                }
            }
        }

    }
}